import { createStore, Commit } from 'vuex'
import axios, { AxiosRequestConfig } from 'axios'

export interface ImageProps {
  url?: string,
  _id?: string,
  createAd?: string
}
export interface ColumnProps {
  _id?: string
  author?: string
  title?: string
  avatar?: ImageProps
  description?: string
  createdAt?: string
}
export interface UserProps {
  isLogin?: boolean
  nickName?: string;
  avatar?: ImageProps;
  _id?: string;
  column?: string;
  email?:string;
}
export interface PostProps {
  _id?: string;
  title?: string;
  excerpt?: string
  content?: string;
  image?: ImageProps;
  createdAt?: string;
  column?: string;
  author?: string | UserProps
  isHTML?: boolean
}
export interface GlobalErrorProps {
  status: boolean
  message?: string
}
export interface GlobalProps {
  error: GlobalErrorProps
  token: string,
  loading: boolean,
  columns: ColumnProps[],
  posts: PostProps[],
  user: UserProps,
  currentPost?:PostProps
}
interface LoginProps {
  email: string;
  password: string;
}

const getAndCommit = async (url:string, commit:Commit, mutationName:string) => {
  const { data: res } = await axios.get(url)
  commit(mutationName, res.data)
  return res.data
}

const postAndCommit = async (url:string, payload:LoginProps, commit:Commit, mutationName:string) => {
  const { data: res } = await axios.post(url, payload)
  commit(mutationName, res)
}

const asyncAndCommit = async (url: string, commit:Commit, mutationName:string, config: AxiosRequestConfig = { method: 'get' }) => {
  const { data: res } = await axios(url, config)
  commit(mutationName, res)
}

const store = createStore<GlobalProps>({
  state: {
    error: { status: false },
    token: localStorage.getItem('token') || '',
    loading: false,
    columns: [],
    posts: [],
    user: { isLogin: false, nickName: 'zhangsan', column: '1' }
  },
  mutations: {
    createPost (state, newPost:PostProps) {
      state.posts.push(newPost)
    },
    fetchColumns (state, rawData) {
      state.columns = rawData.list
    },
    fetchColumn (state, rawData) {
      state.columns = [rawData]
    },
    fetchPosts (state, rawData) {
      state.posts = rawData.list
    },
    setLoading (state, status) {
      state.loading = status
    },
    setError (state, e: GlobalErrorProps) {
      state.error = e
    },
    login (state, rawData) {
      const { data: { token } } = rawData
      state.token = token
      localStorage.setItem('token', token)
      axios.defaults.headers.common.Authorization = `Bearer ${token}`
    },
    logout (state) {
      state.token = ''
      localStorage.removeItem('token')
      delete axios.defaults.headers.Authorization
    },
    fetchCurrentUser (state, rawData) {
      state.user = { isLogin: true, ...rawData }
    },
    fetchPost (state, rawData) {
      state.posts = [rawData]
    },
    updatePost (state, rawData) {
      state.posts = state.posts.map(post => {
        if (post._id === rawData._id) {
          return rawData
        } else {
          return post
        }
      })
    }
  },
  actions: {
    fetchColumns (context) {
      return getAndCommit('/api/columns', context.commit, 'fetchColumns')
    },
    fetchColumn (context, cid:string) {
      return getAndCommit(`/api/columns/${cid}`, context.commit, 'fetchColumn')
    },
    fetchPosts (context, cid:string) {
      return getAndCommit(`/api/columns/${cid}/posts`, context.commit, 'fetchPosts')
    },
    login ({ commit }, payload:LoginProps) {
      /* 说一说这里为什么要用return , 如果不用return的话 , 在axios调用dispatch方法
      的时候就会直接调用then方法 , 此时token没有值 , 加上return才能保证返回的promise是
      postAndCommit */
      return postAndCommit('/api/user/login', payload, commit, 'login')
    },
    fetchCurrentUser ({ commit }) {
      return getAndCommit('/api/user/current', commit, 'fetchCurrentUser')
    },
    loginAndFetch ({ dispatch }, payload:LoginProps) {
      return dispatch('login', payload).then(() => {
        dispatch('fetchCurrentUser')
      })
    },
    createPost ({ commit }, payload) {
      return postAndCommit('/api/posts', payload, commit, 'createPost')
    },
    fetchPost ({ commit }, Cid) {
      return getAndCommit(`/api/posts/${Cid}`, commit, 'fetchPost')
    },
    updatePost ({ commit }, { id, payload }) {
      return asyncAndCommit(`/api/posts/${id}`, commit, 'updatePost', {
        method: 'patch',
        data: payload
      })
    }
  },
  getters: {
    getColumnById (state) {
      return (Cid:string) => state.columns.find((c:ColumnProps) => {
        return c._id === Cid
      })
    },
    getPostsByCid (state) {
      return (Cid:string) => state.posts.filter((post:PostProps) => post.column === Cid)
    },
    getPostByCid (state) {
      return (Cid:string) => state.posts.filter((post: PostProps) => post._id === Cid)[0]
    }
  }
})
export default store
